package maze;

import java.awt.Canvas;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.RenderingHints;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.List;
import maze.levels.Level;
import maze.levels.Player;
import maze.levels.Question;
import maze.paint.SelectionMenu;
import maze.xml.XMLParser;
import maze.paint.StringPrinter;

/**
 *
 * @author Dennis Nijssen
 */
public class Game extends Canvas implements KeyListener {
    private MainApplet mainApplet;
    private String xml;
    
    private Maze maze;
    private SelectionMenu menu, questionMenu;
    private StringPrinter knowledge;
    
    private Player player;
    //private Question question;
    private List<Question> questions;

    public static int level;
    public static List<Level> levels;
    
    private final static int rowAmount = 15;
    private final static int columnAmount = 12;
    public final static Font font = new Font("Arial", Font.PLAIN, 24);
    public final static int fontSize = 25;
    
    public static URL baseURL;
    
    public enum State {
        GAME, GAME_PAINTED, QUESTION, MENU, KNOW_IT_ALL;
    }
    public static State STATE;
    
    private void startGame() {
        try {
            XMLParser parser = new XMLParser(baseURL, xml);
            levels = parser.getLevels(menu.getHighlighted());
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        
        setState(State.GAME);
        level = 0;
        setLevel(level);
    }
    
    public Game(MainApplet mainApplet, URL baseURL, String xml) {        
        this.mainApplet = mainApplet;
        Game.baseURL = baseURL;
        this.xml = xml;
        
        setState(State.MENU);
        
        addKeyListener(this);
        
        setFocusable(true);
        requestFocus();
    }
    
    private void setLevel(int level) {
        if(level > 0) {
            levels.get(level - 1).stopAudio();
        }
        levels.get(level).playAudio();
        
        //STATE = State.KNOW_IT_ALL;
        // Geen vragen? Zet de eerste vragen
        if(questions == null) {
            questions = levels.get(level).getQuestions();
        } else { // Anders voeg de vragen toe aan de ArrayList met vragen
            questions.addAll(levels.get(level).getQuestions());
        }
        
        maze = new Maze(rowAmount, columnAmount, getWidth(), getHeight());
        maze.putQuestions(questions);
        maze.putKnowledge(levels.get(level).getKnowledge());
        player = new Player(maze, levels.get(level).getAnimal(), 0, 0);
        setState(State.GAME);
    }
    
    private void draw(Graphics g) {
        Graphics2D g2d = (Graphics2D)g;
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, 
                RenderingHints.VALUE_ANTIALIAS_ON);
        
        switch(STATE) {
            case GAME:
                maze.paint(g2d);
                player.paint(g2d, maze.getScaleX(), maze.getScaleY());
                break;
            case GAME_PAINTED:
                maze.paintCell(g2d, player.getCurrentCell().getRow(), player.getCurrentCell().getColumn());
                maze.paintCell(g2d, player.getPreviousCell().getRow(), player.getPreviousCell().getColumn());
                player.paint(g2d, maze.getScaleX(), maze.getScaleY());
                break;
            case QUESTION:
                questionMenu.paint(g, getWidth() - 1, getHeight() - 1);
                break;
            case MENU:
                menu.paint(g, getWidth() - 1, getHeight() - 1);
                
                /*int pos_y = 70;
                int pos_x = 50;
                for(int x = 0; x < XMLParser.types.length; x++) {
                    if(x == menu_pos) {
                        g2d.setColor(Color.red);
                        g2d.drawString(XMLParser.types[x], pos_x, pos_y);
                        g2d.setColor(Color.black);
                    } else {
                        g2d.drawString(XMLParser.types[x], pos_x, pos_y);
                    }
                    pos_y += 70;
                }*/
                break;
            case KNOW_IT_ALL:
                //The newest knowItall is always at the end of the list.
                //g2d.drawString(levels.get(level).getKnowledge.get(knowledge.size() - 1).getDescription(), posX, posY);
                knowledge.paint(g, getWidth() - 1, getHeight() - 1);
                break;
        }
    }
    
    /**
     * Set STATE to state and perform default actions associated with that state.
     * @param state 
     */
    public void setState(State state) {
        boolean repaint = false;
        switch(state) {
            case QUESTION:
                player.playAudio();
                
                //Convert List<String> to String[]
                String[] answers = new String[player.getCurrentCell().getQuestion().getAnswers().size()];
                for(int x = 0; x < answers.length; x++) {
                    answers[x] = player.getCurrentCell().getQuestion().getAnswers().get(x);
                }
                String question = player.getCurrentCell().getQuestion().getDescription();
                this.questionMenu = new SelectionMenu(answers, question, fontSize, 0, 0);
                repaint = true;
                break;
            case GAME:
                repaint = true;
                break;
            case KNOW_IT_ALL:
                String[] text = new String[1];
                text[0] = player.getCurrentCell().getKnowledge().getDescription();
                this.knowledge = new StringPrinter(text, fontSize, 0, 0);
                repaint = true;
                break;
            case MENU:
                this.menu = new SelectionMenu(XMLParser.types, "Wat voor dier wil je hebben?", fontSize, 0, 0);
                repaint = true;
                break;
        }
        STATE = state;
        
        if(repaint) {
            repaint();
        }
    }
    
    @Override
    public void paint(Graphics g) {
        
        //if(STATE == State.GAME) {
        //    maze.repaint();
        //}
        //else {
            Image offscreenImage = createImage(getWidth(), getHeight());
            Graphics offscreenGraphics = offscreenImage.getGraphics();
        
            draw(offscreenGraphics);
            
            if(STATE == State.GAME_PAINTED) {
                STATE = State.GAME;
            }
            g.drawImage(offscreenImage, 0, 0, this);
        //}
    }

    @Override
    public void keyTyped(KeyEvent e) {
        // Not supported yet
    }

    @Override
    public void keyPressed(KeyEvent e) {
        keyAction(e);
    }

    @Override
    public void keyReleased(KeyEvent e) {
        // Not supported yet
    }
    
    private void keyAction(KeyEvent e) {
        if(STATE == State.GAME || STATE == State.GAME_PAINTED) {
            setState(State.GAME_PAINTED);
            if(e.getKeyCode() == KeyEvent.VK_W) player.moveUp();
            if(e.getKeyCode() == KeyEvent.VK_S) player.moveDown();
            if(e.getKeyCode() == KeyEvent.VK_A) player.moveLeft();
            if(e.getKeyCode() == KeyEvent.VK_D) player.moveRight();        
            if(e.getKeyCode() == KeyEvent.VK_UP) player.moveUp();
            if(e.getKeyCode() == KeyEvent.VK_DOWN) player.moveDown();
            if(e.getKeyCode() == KeyEvent.VK_LEFT) player.moveLeft();
            if(e.getKeyCode() == KeyEvent.VK_RIGHT) player.moveRight();
            if(e.getKeyCode() == KeyEvent.VK_NUMPAD8) player.moveUp();
            if(e.getKeyCode() == KeyEvent.VK_NUMPAD2) player.moveDown();
            if(e.getKeyCode() == KeyEvent.VK_NUMPAD4) player.moveLeft();
            if(e.getKeyCode() == KeyEvent.VK_NUMPAD6) player.moveRight();
            if(e.getKeyCode() == KeyEvent.VK_R) setState(State.GAME);
            
            
            if(player.hitQuestion()) {
                setState(State.QUESTION);
            }
            if(player.hitKnowledge()) {
                setState(State.KNOW_IT_ALL);
            }
        } else if(STATE == State.QUESTION) {
            if(e.getKeyCode() == KeyEvent.VK_W) questionMenu.move(SelectionMenu.Direction.UP);
            if(e.getKeyCode() == KeyEvent.VK_S) questionMenu.move(SelectionMenu.Direction.DOWN);
            if(e.getKeyCode() == KeyEvent.VK_UP) questionMenu.move(SelectionMenu.Direction.UP);
            if(e.getKeyCode() == KeyEvent.VK_DOWN) questionMenu.move(SelectionMenu.Direction.DOWN);
            if(e.getKeyCode() == KeyEvent.VK_NUMPAD8) questionMenu.move(SelectionMenu.Direction.UP);
            if(e.getKeyCode() == KeyEvent.VK_NUMPAD2) questionMenu.move(SelectionMenu.Direction.DOWN);
            
            if(e.getKeyCode() == KeyEvent.VK_ENTER) player.getCurrentCell().getQuestion().selectAnswer(questionMenu.getHighlighted());
        } else if(STATE == State.MENU) {
            switch(e.getKeyCode()) {
                case KeyEvent.VK_W:
                case KeyEvent.VK_UP:
                case KeyEvent.VK_NUMPAD8:
                    menu.move(SelectionMenu.Direction.UP);
                    break;
                case KeyEvent.VK_S:
                case KeyEvent.VK_DOWN:
                case KeyEvent.VK_NUMPAD2:
                    menu.move(SelectionMenu.Direction.DOWN);
                    break;
                case KeyEvent.VK_ENTER:
                    startGame();
                    break;
            }
        }
        else if(STATE == State.KNOW_IT_ALL) {
            switch(e.getKeyCode()) {
                case KeyEvent.VK_ENTER:
                    player.getCurrentCell().getKnowledge().setVisisted(true);
                    setState(State.GAME);
                    break;
            }
        }
          
        switch(levelFinished()) {
            case 1:
                setLevel(++level);
                break;
            case 2:
                // Game over, send data
                sendData();
                break;
        }
        
        if(STATE == State.GAME_PAINTED) {
            Cell cell = player.getCurrentCell();
            Cell prevCell = player.getPreviousCell();
            
            int scaleX = 1, scaleY = 1;
            int row = cell.getRow(), column = cell.getColumn();;
            //Calculate the starting point of the paintjob.
            if(cell.getColumn() == prevCell.getColumn()) {
                scaleX = 2;
                if(cell.getRow() > prevCell.getRow()) {
                    row = prevCell.getRow();
                }
            }
            else {
                scaleY = 2;
                if(cell.getColumn() > prevCell.getColumn()) {
                    column = prevCell.getColumn();
                }
            }
            
            repaint((int)maze.scaleX(row), (int)maze.scaleY(column), 
                    (int)maze.scaleX(scaleX), (int)maze.scaleY(scaleY));
            return;
        }
        repaint();
    }

    // 0 = level not finished, 1 = level finished but game is not, 2 = game over
    public int levelFinished() {
        int ret = 0;
        
        if(STATE == State.MENU) {
            return 0;
        }
        
        int totalQuestions = questions.size();
        int questionsAnswered = 0;
        
        // Loop alle vragen na en kijk of ze al beantwoord/bezocht zijn
        for(Question q : questions) {
            if(q.getVisited()) questionsAnswered++;
        }
        
        if(questionsAnswered == totalQuestions && 
                player.getCurrentCell().getRow() == (maze.getRowAmount() - 1) &&
                player.getCurrentCell().getColumn() == (maze.getColumnAmount() - 1)) {
            ret = 1;
            if(level == levels.size()) {
                ret = 2;
            }
        }
        
        if(ret == 1 && (level == levels.size())) {
            ret = 2;
        }
        
        return ret;
    }
    
    private void sendData() {
        StringBuilder content = new StringBuilder();
        
        content.append("&typedier=");
        content.append(XMLParser.types[menu.getHighlighted()]);
        
        for(Question q : questions) {
            content.append("&arr[]=");
            content.append(q.getQuestion().replaceAll(" ", "%20"));
            content.append("&arr[]=");
            content.append(q.getSelectedAnswer().replaceAll(" ", "%20"));
        }
        
        mainApplet.jsSetData(content.toString());
    }
}
